home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #2 / Ham Radio 2000 - Volume 2.iso / HAMV2 / TCP_IP / TNOS230S / SMTPCLI.C < prev    next >
Encoding:
C/C++ Source or Header  |  1997-09-07  |  34.4 KB  |  1,413 lines

  1. /*
  2.  *    CLIENT routines for Simple Mail Transfer Protocol ala RFC821
  3.  *    A.D. Barksdale Garbee II, aka Bdale, N3EUA
  4.  *    Copyright 1986 Bdale Garbee, All Rights Reserved.
  5.  *    Permission granted for non-commercial copying and use, provided
  6.  *    this notice is retained.
  7.  *     Modified 14 June 1987 by P. Karn for symbolic target addresses,
  8.  *    also rebuilt locking mechanism
  9.  *    Copyright 1987 1988 David Trulli, All Rights Reserved.
  10.  *    Permission granted for non-commercial copying and use, provided
  11.  *    this notice is retained.
  12.  */
  13. /* Mods by G1EMM and PA0GRI */
  14. #include "global.h"
  15. #include "commands.h"
  16. #ifndef MSDOS
  17. #include <time.h>
  18. #include <setjmp.h>
  19. #endif
  20. #ifdef UNIX
  21. #ifdef BSD
  22. #undef BSD
  23. #endif
  24. #endif
  25. #include <sys/stat.h>
  26. #include <stdarg.h>
  27. #include "mbuf.h"
  28. #include "proc.h"
  29. #include "socket.h"
  30. #ifdef    LZW
  31. #include "lzw.h"
  32. #else
  33. #include "tcp.h"
  34. #endif
  35. #include "smtp.h"
  36. #include "dirutil.h"
  37. #include "session.h"
  38. #include "mailutil.h"
  39.  
  40. #if !defined(_lint)
  41. static char rcsid[] OPTIONAL = "$Id: smtpcli.c,v 1.33 1997/09/07 21:18:28 root Exp root $";
  42. #endif
  43.  
  44. #ifdef HOPPER
  45. static int UseHopper = 0;        /* G8FSL SMTP hopper default OFF */
  46. static int dohopper (int argc, char *argv[], void *p);    /* g8fsl */
  47. #endif
  48.  
  49. #ifdef UNIX
  50. extern void sm_status (int pos, char *str);
  51. #endif
  52.  
  53. struct timer Smtpcli_t;
  54. static uint32 Gateway;
  55.  
  56. int Rewritetrace = 0;        /* used for rewrite trace mode */
  57.  
  58. #ifdef SMTPTRACE
  59. static unsigned short Smtptrace = 0;    /* used for trace level */
  60. static int dosmtptrace (int argc, char *argv[], void *p);
  61. static char smtp_recv[] = "smtpcli recv: %s\n";
  62. #endif
  63.  
  64. static unsigned short Smtpmaxcli = MAXSESSIONS;    /* the max client connections allowed */
  65. static int Smtpsessions = 0;    /* number of client connections
  66.                     * currently open */
  67.  
  68. #ifdef    LZW
  69. int Smtpslzw = 1;
  70. static int Smtpclzw = 1;
  71. #endif
  72.  
  73. static int Smtpbatch = 0;
  74.  
  75. #ifdef MBFWD
  76. int Smtpbidcheck = 1;
  77. int Smtpheaders = 1;
  78. #endif
  79.  
  80. int Smtpmode = 0;
  81. int Smtpquiet = 0;
  82. static int UseMX = 0;        /* use MX records in domain lookup */
  83. int SMTPnotify = 1;
  84.  
  85. static struct smtpcli *cli_session[MAXSESSIONS];    /* queue of client sessions  */
  86.  
  87. static int dorewritechk (int argc, char *argv[], void *p);
  88. static int dorewritetr (int argc, char *argv[], void *p);
  89. static void dosmtptick (int i, void *p1, void *p2);
  90. static void dosmtpkick (int i, void *p1, void *p2);
  91. static void del_job (struct smtp_job * jp);
  92. static void del_session (struct smtpcli * cb);
  93. static int dogateway (int argc, char *argv[], void *p);
  94. static int dosmtpmaxcli (int argc, char *argv[], void *p);
  95. static int dotimer (int argc, char *argv[], void *p);
  96. static int doquiet (int argc, char *argv[], void *p);
  97.  
  98. #ifdef LZW
  99. static int doclzw (int argc, char *argv[], void *p);
  100. static int doslzw (int argc, char *argv[], void *p);
  101. #endif
  102.  
  103. #ifdef HOLDMODS
  104. static int doholdscan (int argc, char *argv[], void *p);
  105. #endif
  106.  
  107. static int donotify (int argc, char *argv[], void *p);
  108. static int dousemx (int argc, char *argv[], void *p);
  109. static int dosmtpkill (int argc, char *argv[], void *p);
  110. static int dosmtplist (int argc, char *argv[], void *p);
  111. static int dobatch (int argc, char *argv[], void *p);
  112. static void execjobs (void);
  113. static int getresp (struct smtpcli * ftp, char *usebuf, int mincode);
  114. static void logerr (struct smtpcli * cb, char *line);
  115. static struct smtpcli *lookup (uint32 destaddr);
  116. static struct smtpcli *newcb (void);
  117. static int next_job (struct smtpcli * cb);
  118. static void retmail (struct smtpcli * cb);
  119. static void sendcmd (struct smtpcli * cb, const char *fmt,...);
  120. static int smtpsendfile (struct smtpcli * cb);
  121. static int setsmtpmode (int argc, char *argv[], void *p);
  122. static void check_qtime (register struct smtpcli * cb);
  123. static struct smtp_job *setupjob (struct smtpcli * cb, char *id, char *from);
  124. static void smtp_send (int unused, void *cb1, void *p);
  125. static int smtpkick (int argc, char *argv[], void *p);
  126. static int dosmtpt4 (int argc, char *argv[], void *p);
  127.  
  128. #ifdef MBFWD
  129. static int dobidcheck (int argc, char *argv[], void *p);
  130. static int doheaders (int argc, char *argv[], void *p);
  131. #endif
  132.  
  133. static int dodtimeout (int argc, char *argv[], void *p);
  134.  
  135. static struct cmds Smtpcmds[] =
  136. {
  137.     { "batch",        dobatch,    0, 0, NULLCHAR },
  138. #ifdef MBFWD
  139.     { "bidcheck",        dobidcheck,    0, 0, NULLCHAR },
  140. #endif
  141.     { "dtimeout",        dodtimeout,    0, 0, NULLCHAR },
  142.     { "gateway",        dogateway,    0, 0, NULLCHAR },
  143. #ifdef MBFWD
  144.     { "headers",        doheaders,    0, 0, NULLCHAR },
  145. #endif
  146. #ifdef HOLDMODS
  147.     { "holdscanall",    doholdscan,    0, 0, NULLCHAR },
  148. #endif
  149. #ifdef HOPPER
  150.     { "hopper",        dohopper,    0, 0, NULLCHAR },
  151. #endif
  152.     { "kick",        smtpkick,    0, 0, NULLCHAR },
  153.     { "kill",        dosmtpkill,    0, 2, "smtp kill <jobnumber>" },
  154.     { "list",        dosmtplist,    0, 0, NULLCHAR },
  155.     { "maxclients",        dosmtpmaxcli,    0, 0, NULLCHAR },
  156.     { "mode",        setsmtpmode,    0, 0, NULLCHAR },
  157.     { "notify",        donotify,    0, 0, NULLCHAR },
  158.     { "quiet",        doquiet,    0, 0, NULLCHAR },
  159. #ifdef    LZW
  160.     { "reclzw",        doslzw,        0, 0, NULLCHAR },
  161. #endif
  162.     { "rewritecheck",    dorewritechk,    0, 2, "smtp rewritecheck address" },
  163.     { "rewritetrace",    dorewritetr,    0, 0, NULLCHAR },
  164. #ifdef    LZW
  165.     { "sendlzw",        doclzw,        0, 0, NULLCHAR },
  166. #endif
  167.     { "timer",        dotimer,    0, 0, NULLCHAR },
  168. #ifdef SMTPTRACE
  169.     { "trace",        dosmtptrace,    0, 0, NULLCHAR },
  170. #endif
  171.     { "t4",            dosmtpt4,    0, 0, NULLCHAR },
  172.     { "usemx",        dousemx,    0, 0, NULLCHAR },
  173.     { NULLCHAR,        NULL,        0, 0, NULLCHAR }
  174. };
  175.  
  176.  
  177.  
  178. int
  179. dosmtp (int argc, char *argv[], void *p)
  180. {
  181.     return subcmd (Smtpcmds, argc, argv, p);
  182. }
  183.  
  184.  
  185.  
  186. int Sholdscanall = 0;
  187.  
  188. #ifdef HOLDMODS
  189. static int
  190. doholdscan (int argc, char *argv[], void *p OPTIONAL)
  191. {
  192.     return setbool (&Sholdscanall, "Scan all messages with wordhold/userhold files", argc, argv);
  193. }
  194. #endif
  195.  
  196.  
  197.  
  198. static int Sdtimer = 0;
  199.  
  200. static int
  201. dodtimeout (int argc, char *argv[], void *p OPTIONAL)
  202. {
  203.     return setint (&Sdtimer, "Delivery timeout (hours)", argc, argv);
  204. }
  205.  
  206.  
  207.  
  208. static int Smtpt4;
  209.  
  210. static int
  211. dosmtpt4 (int argc, char *argv[], void *p OPTIONAL)
  212. {
  213.     return setint (&Smtpt4, "SMTP T4", argc, argv);
  214. }
  215.  
  216.  
  217.  
  218. static int
  219. dobatch (int argc, char *argv[], void *p OPTIONAL)
  220. {
  221.     return setbool (&Smtpbatch, "SMTP batching", argc, argv);
  222. }
  223.  
  224.  
  225.  
  226. #ifdef MBFWD
  227. static int
  228. doheaders (int argc, char *argv[], void *p OPTIONAL)
  229. {
  230.     return setbool (&Smtpheaders, "SMTP RFC-822 headers in data for local BBS messages", argc, argv);
  231. }
  232.  
  233.  
  234.  
  235. static int
  236. dobidcheck (int argc, char *argv[], void *p OPTIONAL)
  237. {
  238.     return setbool (&Smtpbidcheck, "SMTP bid checking", argc, argv);
  239. }
  240. #endif
  241.  
  242.  
  243.  
  244. static int
  245. donotify (int argc, char *argv[], void *p OPTIONAL)
  246. {
  247.     return setbool (&SMTPnotify, "SMTP incoming mail notification", argc, argv);
  248. }
  249.  
  250.  
  251.  
  252. #ifdef LZW
  253. static int
  254. doclzw (int argc, char *argv[], void *p OPTIONAL)
  255. {
  256.     return setbool (&Smtpclzw, "SMTP send lzw", argc, argv);
  257. }
  258.  
  259.  
  260.  
  261. static int
  262. doslzw (int argc, char *argv[], void *p OPTIONAL)
  263. {
  264.     return setbool (&Smtpslzw, "SMTP recv lzw", argc, argv);
  265. }
  266. #endif
  267.  
  268.  
  269.  
  270. static int
  271. doquiet (int argc, char *argv[], void *p OPTIONAL)
  272. {
  273.     return setbool (&Smtpquiet, "SMTP quiet", argc, argv);
  274. }
  275.  
  276.  
  277.  
  278. static int
  279. dousemx (int argc, char *argv[], void *p OPTIONAL)
  280. {
  281.     return setbool (&UseMX, "MX records used", argc, argv);
  282. }
  283.  
  284.  
  285.  
  286. static int
  287. dosmtpmaxcli (int argc, char *argv[], void *p OPTIONAL)
  288. {
  289.     return setshort (&Smtpmaxcli, "Max clients", argc, argv);
  290. }
  291.  
  292.  
  293.  
  294. static int
  295. setsmtpmode (int argc, char *argv[], void *p OPTIONAL)
  296. {
  297.     if (argc < 2)
  298.         tprintf ("smtp mode: %s\n", (Smtpmode & QUEUE) ? "queue" : "route");
  299.     else {
  300.         switch (*argv[1]) {
  301.             case 'q':
  302.                 Smtpmode |= QUEUE;
  303.                 break;
  304.             case 'r':
  305.                 Smtpmode &= ~QUEUE;
  306.                 break;
  307.             default:
  308.                 tputs ("Usage: smtp mode [queue | route]\n");
  309.                 break;
  310.         }
  311.     }
  312.     return 0;
  313. }
  314.  
  315.  
  316.  
  317. static int
  318. dogateway (int argc, char *argv[], void *p OPTIONAL)
  319. {
  320. uint32 n;
  321.  
  322.     if (argc < 2)
  323.         tprintf ("%s\n", inet_ntoa (Gateway));
  324.     else if (!stricmp (argv[1], "none"))
  325.         Gateway = 0;
  326.     else if ((n = resolve (argv[1])) == 0) {
  327.         tprintf (Badhost, argv[1]);
  328.         return 1;
  329.     } else
  330.         Gateway = n;
  331.     return 0;
  332. }
  333.  
  334.  
  335.  
  336. #ifdef HOPPER
  337. static int
  338. dohopper (int argc, char *argv[], void *p OPTIONAL)
  339. {
  340.     return setbool (&UseHopper, "G8FSL mail hopper", argc, argv);
  341. }
  342. #endif
  343.  
  344.  
  345.  
  346. #ifdef SMTPTRACE
  347. static int
  348. dosmtptrace (int argc, char *argv[], void *p OPTIONAL)
  349. {
  350.     return setshort (&Smtptrace, "SMTP tracing", argc, argv);
  351. }
  352. #endif
  353.  
  354.  
  355.  
  356. static int
  357. dorewritechk (int argc OPTIONAL, char *argv[], void *p OPTIONAL)
  358. {
  359. int oldtrace;
  360. char *destination;
  361.  
  362.     oldtrace = Rewritetrace;
  363.     Rewritetrace = 1;
  364.     destination = rewrite_address (argv[1], 0);
  365.     Rewritetrace = oldtrace;
  366.     tprintf ("Address '%s' rewrites to '%s'\n", argv[1], destination);
  367.     free (destination);
  368.     return 0;
  369. }
  370.  
  371.  
  372.  
  373. static int
  374. dorewritetr (int argc, char *argv[], void *p OPTIONAL)
  375. {
  376.     return setbool (&Rewritetrace, "Rewrite tracing", argc, argv);
  377. }
  378.  
  379.  
  380.  
  381. /* list jobs waiting to be sent in the mqueue */
  382. static int
  383. dosmtplist (int argc OPTIONAL, char *argv[] OPTIONAL, void *p OPTIONAL)
  384. {
  385. char tstring[80];
  386. char line[20];
  387. char host[LINELEN];
  388. char to[LINELEN];
  389. char from[LINELEN];
  390. char *cp;
  391. char status;
  392. int flowsave;
  393. struct stat stbuf;
  394. struct tm *tminfo;
  395. FILE *fp;
  396.  
  397.     flowsave = Current->flowmode;
  398.     Current->flowmode = 1;    /* Enable the more mechanism */
  399.     tputs ("S     Job    Size  Date  Time Host                 From\n");
  400.     (void) filedir (Mailqueue, 0, line);
  401.     while (line[0] != '\0') {
  402.         sprintf (tstring, "%s/%s", Mailqdir, line);
  403.         if ((fp = fopen (tstring, READ_TEXT)) == NULLFILE) {
  404.             tprintf ("Can't open %s: %s\n", tstring, SYS_ERRLIST(errno));
  405.             continue;
  406.         }
  407.         if ((cp = strrchr (line, '.')) != NULLCHAR)
  408.             *cp = '\0';
  409.         sprintf (tstring, "%s/%s.lck", Mailqdir, line);
  410.         if (access (tstring, 0))
  411.             status = ' ';
  412.         else
  413.             status = 'L';
  414.         sprintf (tstring, "%s/%s.txt", Mailqdir, line);
  415.         if (stat (tstring, &stbuf) == -1) {
  416.             sprintf (tstring, "%s/%s.lck", Mailqdir, line);
  417.             unlink (tstring);
  418.             sprintf (tstring, "%s/%s.wrk", Mailqdir, line);
  419.             unlink (tstring);
  420.             goto skip;
  421.         }
  422.         tminfo = localtime (&stbuf.st_ctime);
  423.         host[0] = from[0] = 0;
  424.         (void) fgets (host, sizeof (host), fp);
  425.         rip (host);
  426.         (void) fgets (from, sizeof (from), fp);
  427.         rip (from);
  428.         tprintf ("%c %7s %7ld %02d/%02d %02d:%02d %-20s %s\n        ",
  429.              status, line, (long) stbuf.st_size,
  430.              tminfo->tm_mon + 1,
  431.              tminfo->tm_mday,
  432.              tminfo->tm_hour,
  433.              tminfo->tm_min,
  434.              host, from);
  435.         while (fgets (to, sizeof (to), fp) != NULLCHAR) {
  436.             rip (to);
  437.             tprintf ("%s ", to);
  438.         }
  439.         tputc ('\n');
  440. skip:
  441.         (void) fclose (fp);
  442.         kwait (NULL);
  443.         (void) filedir (Mailqueue, 1, line);
  444.     }
  445.     Current->flowmode = flowsave;
  446.     return 0;
  447. }
  448.  
  449.  
  450.  
  451. /* kill a job in the mqueue */
  452. static int
  453. dosmtpkill (int argc OPTIONAL, char *argv[], void *p OPTIONAL)
  454. {
  455. char s[SLINELEN];
  456. char *cp, c;
  457.  
  458.     sprintf (s, "%s/%s.lck", Mailqdir, argv[1]);
  459.     cp = strrchr (s, '.');
  460.     if (cp != NULLCHAR)    {    /* shouldn't occur */
  461.         if (!access (s, 0)) {
  462.             Current->ttystate.echo = Current->ttystate.edit = 0;
  463.             c = (char) keywait ("Warning, job is locked by SMTP. Remove (y/n)? ", 0);
  464.             Current->ttystate.echo = Current->ttystate.edit = 1;
  465.             if (c != 'y')
  466.                 return 0;
  467.             (void) unlink (s);
  468.         }
  469.         strcpy (cp, ".wrk");
  470.         if (unlink (s))
  471.             tprintf ("Job id %s not found\n", argv[1]);
  472.         strcpy (cp, ".txt");
  473.         (void) unlink (s);
  474.     }
  475.     return 0;
  476. }
  477.  
  478.  
  479.  
  480. /* Set outbound spool scan interval */
  481. static int
  482. dotimer (int argc, char *argv[], void *p OPTIONAL)
  483. {
  484.     if (argc < 2) {
  485.         tprintf ("smtp timer = %lu/%lu\n", read_timer (&Smtpcli_t) / 1000L,
  486.              dur_timer (&Smtpcli_t) / 1000L);
  487.         return 0;
  488.     }
  489.     Smtpcli_t.func = (void (*)(void *)) smtptick;    /* what to call on timeout */
  490.     Smtpcli_t.arg = NULL;    /* dummy value */
  491.     set_timer (&Smtpcli_t, atol (argv[1]) * 1000L);    /* set timer duration */
  492.     start_detached_timer (&Smtpcli_t);    /* and fire it up */
  493.     return 0;
  494. }
  495.  
  496.  
  497.  
  498. static void
  499. dosmtpkick (int i OPTIONAL, void *p1, void *p2)
  500. {
  501. uint32 addr = 0;
  502.  
  503.     if ((int) p2 > 1 && (addr = resolve ((char *) p1)) == 0)
  504.         tprintf (Badhost, (char *) p1);
  505.     else
  506.         dosmtptick (0, (void *) addr, (void *) 0);
  507.     if (p1)
  508.         free (p1);
  509. }
  510.  
  511.  
  512.  
  513. static int
  514. smtpkick (int argc, char *argv[], void *p OPTIONAL)
  515. {
  516.     (void) newproc ("smtp client", 1024, dosmtpkick, 0, (argc > 1) ? (void *) strdup (argv[1]) : (void *) 0, (void *) argc, 0);
  517.     return 0;
  518. }
  519.  
  520.  
  521.  
  522. void
  523. smtptick (void *t)
  524. {
  525.     (void) newproc ("smtp client", 1024, dosmtptick, 0, t, (void *) 0, 0);
  526. }
  527.  
  528.  
  529.  
  530. /* This is the routine that gets called every so often to do outgoing
  531.  * mail processing. When called with a null argument, it runs the entire
  532.  * queue; if called with a specific non-zero IP address from the remote
  533.  * kick server, it only starts up sessions to that address.
  534.  */
  535. static void
  536. dosmtptick (int t OPTIONAL, void *p1, void *p2 OPTIONAL)
  537. {
  538. register struct smtpcli *cb;
  539. struct smtp_job *jp;
  540. struct list *ap;
  541. char tmpstring[LINELEN], wfilename[13], prefix[9];
  542. char from[LINELEN], to[LINELEN];
  543. char *cp, *cp1;
  544. uint32 destaddr, target;
  545. FILE *wfile;
  546. static int Ssmtpcli = 0;
  547.  
  548.     target = (uint32) p1;
  549. #ifdef SMTPTRACE
  550.     if (Smtptrace > 5)
  551.         tcmdprintf ("smtp daemon entered, target = %s\n", inet_ntoa (target));
  552. #endif
  553.     /* permit only one general purpose smtp client at a time */
  554.     if (!target) {
  555.         if (Ssmtpcli) {
  556.             start_detached_timer (&Smtpcli_t);
  557.             return;
  558.         } else
  559.             Ssmtpcli = 1;
  560.     }
  561.     kwait (NULL);
  562.     for ((void) filedir (Mailqueue, 0, wfilename); wfilename[0] != '\0'; (void) filedir (Mailqueue, 1, wfilename)) {
  563.  
  564.         /* save the prefix of the file name which it job id */
  565.         cp = wfilename;
  566.         cp1 = prefix;
  567.         while (*cp && *cp != '.')
  568.             *cp1++ = *cp++;
  569.         *cp1 = '\0';
  570.  
  571.         kwait (NULL);
  572.  
  573.         /* first check to see if the *.txt file is missing */
  574.         sprintf (tmpstring, "%s/%s", Mailqdir, wfilename);
  575.         strcpy (&tmpstring[strlen (tmpstring) - 3], "txt");
  576.         if (access (tmpstring, 0)) {
  577.             /* it's missing, remove *.wrk and *.lck (if exists) */
  578.             sprintf (tmpstring, "%s/%s", Mailqdir, wfilename);
  579.             unlink (tmpstring);
  580.             rmlock (Mailqdir, prefix);
  581.             continue;
  582.         }
  583.         /* lock this file from the smtp daemon */
  584.         if (mlock (Mailqdir, prefix))
  585.             continue;
  586.  
  587.         kwait (NULL);
  588.         sprintf (tmpstring, "%s/%s", Mailqdir, wfilename);
  589.         if ((wfile = fopen (tmpstring, READ_TEXT)) == NULLFILE) {
  590.             /* probably too many open files */
  591.             rmlock (Mailqdir, prefix);
  592.             /* continue to next message. The failure may be temporary */
  593.             continue;
  594.         }
  595.         (void) fgets (tmpstring, LINELEN, wfile);    /* read target host */
  596.         rip (tmpstring);
  597.  
  598.         kwait (NULL);
  599.         if ((destaddr = mailroute (tmpstring)) == 0) {
  600.             (void) fclose (wfile);
  601.             tcmdprintf ("** smtp: Unknown address %s\n", tmpstring);
  602.             rmlock (Mailqdir, prefix);
  603.             continue;
  604.         }
  605.         if (target != 0 && destaddr != target) {
  606.             (void) fclose (wfile);
  607.             rmlock (Mailqdir, prefix);
  608.             continue;    /* Not the proper target of a kick */
  609.         }
  610.         kwait (NULL);
  611.         if ((cb = lookup (destaddr)) == NULLSMTPCLI) {
  612.             /* there are enough processes running already */
  613.             if (Smtpsessions >= Smtpmaxcli) {
  614. #ifdef SMTPTRACE
  615.                 if (Smtptrace)
  616.                     tcmdprintf ("smtp daemon: too many processes\n");
  617. #endif
  618.                 log (-1, "smtp daemon: too many processes");
  619.                 (void) fclose (wfile);
  620.                 rmlock (Mailqdir, prefix);
  621.                 break;
  622.             }
  623.             if ((cb = newcb ()) == NULLSMTPCLI) {
  624.                 (void) fclose (wfile);
  625.                 rmlock (Mailqdir, prefix);
  626.                 kwait (NULL);
  627.                 break;
  628.             }
  629.             cb->ipdest = destaddr;
  630.             cb->destname = strdup (tmpstring);
  631.         } else {
  632.             if (cb->lock) {
  633.                 /* This system is already is sending mail lets not
  634.                 * interfere with its send queue.
  635.                 */
  636.                 (void) fclose (wfile);
  637.                 rmlock (Mailqdir, prefix);
  638.                 continue;
  639.             }
  640.         }
  641.  
  642.         kwait (NULL);
  643.         (void) fgets (from, LINELEN, wfile);    /* read from */
  644.         rip (from);
  645.         if ((jp = setupjob (cb, prefix, from)) == NULLJOB) {
  646.             (void) fclose (wfile);
  647.             rmlock (Mailqdir, prefix);
  648.             del_session (cb);
  649.             break;
  650.         }
  651.         kwait (NULL);
  652.         while (wfile != NULLFILE && fgets (to, LINELEN, wfile) != NULLCHAR) {
  653.             rip (to);
  654.             if (addlist (&jp->to, to, DOMAIN, to) == NULLLIST) {
  655.                 (void) fclose (wfile);
  656.                 wfile = NULLFILE;
  657.                 del_session (cb);
  658.             }
  659.             kwait (NULL);
  660.         }
  661.         if (wfile != NULLFILE) {
  662.             (void) fclose (wfile);
  663.             wfile = NULLFILE;
  664.         }
  665. #ifdef SMTPTRACE
  666.         if (Smtptrace > 1) {
  667.             tcmdprintf ("queue job %s From: %s To:", prefix, from);
  668.             for (ap = jp->to; ap != NULLLIST; ap = ap->next)
  669.                 tcmdprintf (" %s", ap->val);
  670.             tcmdprintf ("\n");
  671.         }
  672. #endif
  673.     }
  674.  
  675.     /* start sending that mail */
  676.     execjobs ();
  677.     kwait (NULL);
  678.  
  679.     /* Restart timer */
  680.     start_detached_timer (&Smtpcli_t);
  681.     Ssmtpcli = 0;
  682.     return;
  683. }
  684.  
  685.  
  686.  
  687. /* This is the master state machine that handles a single SMTP transaction.
  688.  * It is called with a queue of jobs for a particular host.
  689.  * The logic is complicated by the "Smtpbatch" variable, which controls
  690.  * the batching of SMTP commands. If Smtpbatch is true, then many of the
  691.  * SMTP commands are sent in one swell foop before waiting for any of
  692.  * the responses. Unfortunately, this breaks many brain-damaged SMTP servers
  693.  * out there, so provisions have to be made to operate SMTP in lock-step mode.
  694.  */
  695. static void
  696. smtp_send (int unused OPTIONAL, void *cb1, void *p OPTIONAL)
  697. {
  698. register struct smtpcli *cb;
  699. register struct list *tp;
  700. struct sockaddr_in fsocket;
  701. char const *cp;
  702. uint32 Altmx[5];
  703. int rcode;
  704. int rcpts;
  705. int goodrcpt;
  706. int i;
  707. int smtpbatch;
  708. int init = 1;
  709. #ifdef    LZW
  710. int lzwmode, lzwbits, ampr;
  711. #endif
  712.  
  713.     cb = (struct smtpcli *) cb1;
  714.     cb->lock = 1;
  715.     fsocket.sin_family = AF_INET;
  716.     fsocket.sin_addr.s_addr = cb->ipdest;
  717.     fsocket.sin_port = IPPORT_SMTP;
  718.  
  719.     cb->s = socket (AF_INET, SOCK_STREAM, 0);
  720.     (void) sockmode (cb->s, SOCK_ASCII);
  721.     (void) setflush (cb->s, -1);    /* We'll explicitly flush before reading */
  722. #ifdef SMTPTRACE
  723.     if (Smtptrace)
  724.         tcmdprintf ("SMTP client Trying...\n");
  725. #endif
  726.     /* Set a timeout for this connection */
  727.     kalarm (Smtpt4 * 1000L);
  728.     if (connect (cb->s, (char *) &fsocket, SOCKSIZE) != 0) {
  729.         kalarm (0L);
  730.         (void) shutdown (cb->s, 2);    /* K2MF: To make sure it doesn't linger around */
  731.         close_s (cb->s);/* to make sure it's closed */
  732.  
  733.         /* Selcuk: Let's try other MX's before Gateway */
  734.         if (UseMX && fsocket.sin_addr.s_addr != Gateway
  735.             && fsocket.sin_addr.s_addr != Ip_addr) {
  736.             if (resolve_amx (cb->destname, fsocket.sin_addr.s_addr, Altmx)) {
  737. #ifdef SMTPTRACE
  738.                 if (Smtptrace > 1)
  739.                     tcmdprintf ("SMTP client trying MX...\n");
  740. #endif
  741.                 for (i = 0; Altmx[i]; i++) {
  742.                     fsocket.sin_addr.s_addr = Altmx[i];
  743.                     /* n5knx: don't deliver to self, that's a loop!  Also, to avoid indirect
  744.                        loops we ignore sites with lower preference than ourselves */
  745.                     if (ismyaddr (fsocket.sin_addr.s_addr))
  746.                         break;
  747.                     cb->s = socket (AF_INET, SOCK_STREAM, 0);
  748.                     (void) sockmode (cb->s, SOCK_ASCII);
  749.                     (void) setflush (cb->s, -1);
  750.                     kalarm (Smtpt4 * 1000L);
  751.                     if (connect (cb->s, (char *) &fsocket, SOCKSIZE) == 0)
  752.                         goto connected;
  753.                     else {
  754.                         kalarm (0L);
  755.                         (void) shutdown (cb->s, 2);    /* K2MF: To make sure it doesn't linger around */
  756.                         close_s (cb->s);
  757.                     }
  758.                 }
  759.             }
  760.         }
  761.         if (Smtpt4 && Gateway && (fsocket.sin_addr.s_addr != Gateway)
  762. #ifdef HOPPER
  763.             && (Gateway != Ip_addr)    /* g8fsl via g0mhd */
  764. # endif
  765.             ) {
  766.             /* Try it via the gateway */
  767.             fsocket.sin_addr.s_addr = Gateway;
  768.             cb->s = socket (AF_INET, SOCK_STREAM, 0);
  769.             (void) sockmode (cb->s, SOCK_ASCII);
  770.             (void) setflush (cb->s, -1);    /* We'll explicitly flush before reading */
  771. #ifdef SMTPTRACE
  772.             if (Smtptrace)
  773.                 tcmdprintf ("SMTP client Trying gateway...\n");
  774. #endif
  775.             /* Set a timeout for this connection */
  776.             kalarm (Smtpt4 * 1000L);
  777.             if (connect (cb->s, (char *) &fsocket, SOCKSIZE) != 0) {
  778.                 kalarm (0L);
  779.                 cp = sockerr (cb->s);
  780.                 (void) shutdown (cb->s, 2);    /* K2MF: To make sure it doesn't linger around */
  781.                 close_s (cb->s);    /* to make sure it's closed */
  782. #ifdef SMTPTRACE
  783.                 if (Smtptrace)
  784.                     tcmdprintf ("Connect failed: %s\n", cp != NULLCHAR ? cp : "");
  785. #endif
  786.                 log (cb->s, "SMTP %s Connect failed: %s", psocket (&fsocket),
  787.                      cp != NULLCHAR ? cp : "");
  788.                 goto quit;
  789.             }
  790.         } else
  791.             goto quit;
  792.     }
  793. connected:
  794.     kalarm (0L);
  795. #ifdef SMTPTRACE
  796.     if (Smtptrace)
  797.         tcmdprintf ("Connected\n");
  798. #endif
  799.     kwait (NULL);
  800.  
  801. #ifdef    LZW
  802.     rcode = getresp (cb, cb->buf, 200);
  803.     if (rcode == -1 || rcode >= 400)
  804.         goto quit;
  805.  
  806. #ifdef __GNUC__
  807.     ampr = (((fsocket.sin_addr.s_addr & 0xff000000LU) >> 24) == 44);
  808. #else
  809.     ampr = (((fsocket.sin_addr.s_addr & 0xff000000) >> 24) == 44);
  810. #endif
  811.  
  812.     /* even if LZW is enabled, don't use it for local connections
  813.        or for hosts not on net 44 */
  814.     if (Smtpclzw && ampr && strncmp (&cb->buf[4], Hostname, strlen (Hostname))) {
  815.         char cpp[LINELEN];
  816.  
  817.         sendcmd (cb, "XLZW %d %d\n", Lzwbits, Lzwmode);
  818.         usflush (cb->s);
  819.         if (recvline (cb->s, (unsigned char *) cpp, sizeof (cpp)) == -1)
  820.             goto quit;
  821.         rip (cpp);
  822. #ifdef    SMTPTRACE
  823.         if (Smtptrace)
  824.             tcmdprintf (smtp_recv, cpp);    /* Display to user */
  825. #endif
  826.         rcode = lzwmode = lzwbits = 0;
  827.         sscanf (cpp, "%d %d %d", &rcode, &lzwbits, &lzwmode);
  828.         if ((rcode >= 200) && (rcode < 300)) {
  829.             smtpbatch = 1;
  830.             if (lzwmode != Lzwmode || lzwbits != Lzwbits) {
  831.                 lzwmode = LZWCOMPACT;
  832.                 lzwbits = LZWBITS;
  833.             }
  834.             lzwinit (cb->s, lzwbits, lzwmode);
  835.         } else
  836.             smtpbatch = Smtpbatch;
  837.     } else
  838.         smtpbatch = Smtpbatch;
  839. #else
  840.     smtpbatch = Smtpbatch;
  841.     if (!smtpbatch) {
  842.         rcode = getresp (cb, NULLCHAR, 200);
  843.         if (rcode == -1 || rcode >= 400)
  844.             goto quit;
  845.     }
  846. #endif
  847.     /* Say HELO */
  848.     sendcmd (cb, "HELO %s\n", Hostname);
  849.     if (!smtpbatch) {
  850.         rcode = getresp (cb, NULLCHAR, 200);
  851.         if (rcode == -1 || rcode >= 400)
  852.             goto quit;
  853.     }
  854.     do {            /* For each message... */
  855.  
  856.         kwait (NULL);
  857.         /* if this file open fails, skip it */
  858.         if ((cb->tfile = fopen (cb->tname, READ_TEXT)) == NULLFILE)
  859.             continue;
  860.         if (!filelength (fileno (cb->tfile))) {
  861.             log (-1, "Skipping null length SMTP data file");
  862.             (void) fclose (cb->tfile);
  863.             cb->tfile = NULLFILE;
  864.             (void) unlink (cb->tname);
  865.             (void) unlink (cb->wname);    /* unlink workfile */
  866.             continue;
  867.         }
  868.         /* Send MAIL and RCPT commands */
  869.         sendcmd (cb, "MAIL FROM:<%s>\n", cb->jobq->from);
  870.         if (!smtpbatch) {
  871.             rcode = getresp (cb, NULLCHAR, 200);
  872.             if (rcode == -1 || rcode >= 400)
  873.                 goto quit;
  874.         }
  875.         rcpts = 0;
  876.         goodrcpt = 0;
  877.         for (tp = cb->jobq->to; tp != NULLLIST; tp = tp->next) {
  878.             sendcmd (cb, "RCPT TO:<%s>\n", tp->val);
  879.             if (!smtpbatch) {
  880.                 rcode = getresp (cb, NULLCHAR, 200);
  881.                 if (rcode == -1)
  882.                     goto quit;
  883.                 if (rcode < 400)
  884.                     goodrcpt = 1;    /* At least one good */
  885.             }
  886.             rcpts++;
  887.         }
  888.         /* Send DATA command */
  889.         sendcmd (cb, "DATA\n");
  890.         kwait (NULL);
  891.         if (!smtpbatch) {
  892.             rcode = getresp (cb, NULLCHAR, 200);
  893.             if (rcode == -1 || rcode >= 400)
  894.                 goto quit;
  895.         }
  896.         if (smtpbatch) {
  897.             /* Now wait for the responses to come back. The first time
  898.              * we do this, we wait first for the start banner and
  899.              * HELO response. In any case, we wait for the response to
  900.              * the MAIL command here.
  901.              */
  902. #ifdef    LZW
  903.             for (i = init ? 2 : 1; i > 0; i--) {
  904. #else
  905.             for (i = init ? 3 : 1; i > 0; i--) {
  906. #endif
  907.                 rcode = getresp (cb, NULLCHAR, 200);
  908.                 if (rcode == -1 || rcode >= 400)
  909.                     goto quit;
  910.             }
  911.             init = 0;
  912.  
  913.             /* Now process the responses to the RCPT commands */
  914.             for (i = rcpts; i != 0; i--) {
  915.                 rcode = getresp (cb, NULLCHAR, 200);
  916.                 if (rcode == -1)
  917.                     goto quit;
  918.                 if (rcode < 400)
  919.                     goodrcpt = 1;    /* At least one good */
  920.             }
  921.             kwait (NULL);
  922.             /* And finally get the response to the DATA command.
  923.              * Some servers will return failure here if no recipients
  924.              * are valid, some won't.
  925.              */
  926.             rcode = getresp (cb, NULLCHAR, 200);
  927.             if (rcode == -1 || rcode >= 400)
  928.                 goto quit;
  929.  
  930.             /* check for no good rcpt on the list */
  931.             if (goodrcpt == 0) {
  932.                 sendcmd (cb, ".\n");    /* Get out of data mode */
  933.                 goto quit;
  934.             }
  935.         }
  936.         /* Send the file. This also closes it */
  937.         (void) smtpsendfile (cb);
  938.  
  939.         /* Wait for the OK response */
  940.         rcode = getresp (cb, NULLCHAR, 200);
  941.         if (rcode == -1)
  942.             goto quit;
  943.         kwait (NULL);
  944.         if ((rcode >= 400) && (rcode < 500))    /* temp failure? */
  945.             check_qtime (cb);
  946.         if ((rcode >= 200 && rcode < 300) || rcode >= 500) {
  947.             /* if a good transfer or permanent failure remove job */
  948.  
  949.             if (cb->errlog != NULLLIST)
  950.                 retmail (cb);
  951. #ifdef STATS_MSG
  952.             STATS_addmsg (1, 1);
  953. #endif
  954.             /* Unlink the textfile */
  955.             (void) unlink (cb->tname);
  956.             (void) unlink (cb->wname);    /* unlink workfile */
  957.             log (cb->s, "SMTP sent job %s To: %s From: %s",
  958.                  cb->jobq->jobname, cb->jobq->to->val, cb->jobq->from);
  959.         }
  960.         if (cb->jobq->next != NULLJOB) {
  961.             /*
  962.              * Reset the remote sendmail's state.
  963.              * This is just to deal with certain stupidities in early
  964.              * versions of sendmail 8.6.  We don't check the value of
  965.              * rcode because we don't really care what it is and some
  966.              * supposedly SMTP compliant mailers don't recognize RSET.
  967.              */
  968.             sendcmd (cb, "RSET\n");
  969.             /* Wait for response */
  970.             rcode = getresp (cb, NULLCHAR, 200);
  971.             if (rcode == -1)
  972.                 goto quit;
  973.         }
  974.     } while (next_job (cb));
  975. quit:
  976.     kwait (NULL);
  977.     sendcmd (cb, "QUIT\n");
  978.     check_qtime (cb);
  979.     if (cb->errlog != NULLLIST) {
  980.         retmail (cb);
  981.         (void) unlink (cb->wname);    /* unlink workfile */
  982.         (void) unlink (cb->tname);    /* unlink text */
  983.     }
  984.     close_s (cb->s);
  985.     if (cb->tfile != NULLFILE)
  986.         (void) fclose (cb->tfile);
  987.     cb->lock = 0;
  988.     del_session (cb);
  989. }
  990.  
  991.  
  992.  
  993. /* check if msg stayed too long in the mqueue */
  994. static void
  995. check_qtime (register struct smtpcli *cb)
  996. {
  997. struct stat tstat;
  998. time_t now;
  999. char tmp[80];
  1000.  
  1001.     if (cb == NULLSMTPCLI || cb->jobq == NULLJOB)
  1002.         return;
  1003.  
  1004.     if (Sdtimer && cb->errlog == NULLLIST) {
  1005.         (void) time (&now);
  1006.         if (cb->tfile == NULLFILE)
  1007.             if ((cb->tfile = fopen (cb->tname, READ_TEXT)) == NULLFILE)
  1008.                 return;
  1009.  
  1010.         (void) fstat (fileno (cb->tfile), &tstat);
  1011.         (void) fclose (cb->tfile);
  1012.         cb->tfile = NULLFILE;
  1013.         if ((now - tstat.st_ctime) > (time_t) (Sdtimer * 3600L)) {
  1014.             sprintf (tmp, " >>> Your message could not be delivered for %d hour(s); giving up!", Sdtimer);
  1015.             logerr (cb, tmp);
  1016.         }
  1017.     }
  1018.     return;
  1019. }
  1020.  
  1021.  
  1022.  
  1023. /* free the message struct and data */
  1024. static void
  1025. del_session (register struct smtpcli *cb)
  1026. {
  1027. register struct smtp_job *jp, *tp;
  1028. register int i;
  1029.  
  1030.     if (cb == NULLSMTPCLI)
  1031.         return;
  1032.     for (i = 0; i < MAXSESSIONS; i++)
  1033.         if (cli_session[i] == cb) {
  1034.             cli_session[i] = NULLSMTPCLI;
  1035.             break;
  1036.         }
  1037.     free (cb->wname);
  1038.     free (cb->tname);
  1039.     free (cb->destname);
  1040.     for (jp = cb->jobq; jp != NULLJOB; jp = tp) {
  1041.         tp = jp->next;
  1042.         del_job (jp);
  1043.     }
  1044.     del_list (cb->errlog);
  1045.     free ((char *) cb);
  1046.     Smtpsessions--;        /* number of connections active */
  1047. }
  1048.  
  1049.  
  1050.  
  1051. static void
  1052. del_job (register struct smtp_job *jp)
  1053. {
  1054.     if (*jp->jobname != '\0')
  1055.         rmlock (Mailqdir, jp->jobname);
  1056.     free (jp->from);
  1057.     del_list (jp->to);
  1058.     free ((char *) jp);
  1059. }
  1060.  
  1061.  
  1062.  
  1063. /* delete a list of list structs */
  1064. void
  1065. del_list (struct list *lp)
  1066. {
  1067. register struct list *tp, *tp1;
  1068.  
  1069.     for (tp = lp; tp != NULLLIST; tp = tp1) {
  1070.         tp1 = tp->next;
  1071.         free (tp->val);
  1072.         free (tp->orig);
  1073.         free ((char *) tp);
  1074.     }
  1075. }
  1076.  
  1077.  
  1078.  
  1079. /* stub for calling mdaemon to return message to sender */
  1080. static void
  1081. retmail (struct smtpcli *cb)
  1082. {
  1083. FILE *infile;
  1084.  
  1085. #ifdef SMTPTRACE
  1086.     if (Smtptrace > 5)
  1087.         tcmdprintf ("smtp job %s returned to sender\n", cb->wname);
  1088. #endif
  1089.     if ((infile = fopen (cb->tname, READ_TEXT)) == NULLFILE)
  1090.         return;
  1091.     /*    mdaemon(infile,cb->jobq->from,cb->errlog,1);    */
  1092.     (void) mdaemon (infile, "sysop", cb->errlog, 1);
  1093.     (void) fclose (infile);
  1094. }
  1095.  
  1096.  
  1097.  
  1098. /* look to see if a smtp control block exists for this ipdest */
  1099. static struct smtpcli *
  1100. lookup (uint32 destaddr)
  1101. {
  1102. register int i;
  1103.  
  1104.     for (i = 0; i < MAXSESSIONS; i++) {
  1105.         if (cli_session[i] == NULLSMTPCLI)
  1106.             continue;
  1107.         if (cli_session[i]->ipdest == destaddr)
  1108.             return cli_session[i];
  1109.     }
  1110.     return NULLSMTPCLI;
  1111. }
  1112.  
  1113.  
  1114.  
  1115. /* create a new  smtp control block */
  1116. static struct smtpcli *
  1117. newcb (void)
  1118. {
  1119. register int i;
  1120. register struct smtpcli *cb;
  1121.  
  1122.     for (i = 0; i < MAXSESSIONS; i++) {
  1123.         if (cli_session[i] == NULLSMTPCLI) {
  1124.             cb = (struct smtpcli *) callocw (1, sizeof (struct smtpcli));
  1125.  
  1126.             cb->wname = mallocw ((unsigned) strlen (Mailqdir) + JOBNAME);
  1127.             cb->tname = mallocw ((unsigned) strlen (Mailqdir) + JOBNAME);
  1128.             cli_session[i] = cb;
  1129.             Smtpsessions++;    /* number of connections active */
  1130.             return (cb);
  1131.         }
  1132.     }
  1133.     return NULLSMTPCLI;
  1134. }
  1135.  
  1136.  
  1137.  
  1138. static void
  1139. execjobs (void)
  1140. {
  1141. register struct smtpcli *cb;
  1142. register int i, insave, outsave;
  1143.  
  1144.     for (i = 0; i < MAXSESSIONS; i++) {
  1145.         kwait (NULL);
  1146.         cb = cli_session[i];
  1147.         if (cb == NULLSMTPCLI)
  1148.             continue;
  1149.         if (cb->lock)
  1150.             continue;
  1151.  
  1152.         sprintf (cb->tname, "%s/%s.txt", Mailqdir, cb->jobq->jobname);
  1153.         sprintf (cb->wname, "%s/%s.wrk", Mailqdir, cb->jobq->jobname);
  1154.  
  1155.         /* This solves the nasty hack in mailbox.c, from Mark ve3dte */
  1156.         insave = Curproc->input;
  1157.         outsave = Curproc->output;
  1158.         Curproc->input = -1;
  1159.         Curproc->output = -1;
  1160.         /* Now we can call newproc with null parent sockets! */
  1161.         (void) newproc ("smtp_send", 1024, smtp_send, 0, cb, NULL, 0);
  1162.         /* now restore parent sockets so parent can continue */
  1163.         Curproc->input = insave;
  1164.         Curproc->output = outsave;
  1165.  
  1166. #ifdef SMTPTRACE
  1167.         if (Smtptrace)
  1168.             tcmdprintf ("Trying Connection to %s\n", inet_ntoa (cb->ipdest));
  1169. #endif
  1170.     }
  1171. }
  1172.  
  1173.  
  1174.  
  1175. /* add this job to control block queue */
  1176. static struct smtp_job *
  1177. setupjob (struct smtpcli *cb, char *id, char *from)
  1178. {
  1179. register struct smtp_job *p1, *p2;
  1180.  
  1181.     p1 = (struct smtp_job *) callocw (1, sizeof (struct smtp_job));
  1182.  
  1183.     p1->from = strdup (from);
  1184.     strncpy (p1->jobname, id, 9);
  1185.     /* now add to end of jobq */
  1186.     if ((p2 = cb->jobq) == NULLJOB)
  1187.         cb->jobq = p1;
  1188.     else {
  1189.         while (p2->next != NULLJOB)
  1190.             p2 = p2->next;
  1191.         p2->next = p1;
  1192.     }
  1193.     return p1;
  1194. }
  1195.  
  1196.  
  1197.  
  1198. /* called to advance to the next job */
  1199. static int
  1200. next_job (cb)
  1201. register struct smtpcli *cb;
  1202. {
  1203.     register struct smtp_job *jp;
  1204.  
  1205.     jp = cb->jobq->next;
  1206.     del_job (cb->jobq);
  1207.     /* remove the error log of previous message */
  1208.     del_list (cb->errlog);
  1209.     cb->errlog = NULLLIST;
  1210.     cb->jobq = jp;
  1211.     if (jp == NULLJOB)
  1212.         return 0;
  1213.     sprintf (cb->tname, "%s/%s.txt", Mailqdir, jp->jobname);
  1214.     sprintf (cb->wname, "%s/%s.wrk", Mailqdir, jp->jobname);
  1215. #ifdef SMTPTRACE
  1216.     if (Smtptrace > 5)
  1217.         tcmdprintf ("sending job %s\n", jp->jobname);
  1218. #endif
  1219.     return 1;
  1220. }
  1221.  
  1222.  
  1223.  
  1224. /* Mail routing function. For now just use the hosts file */
  1225. uint32
  1226. mailroute (char *dest)
  1227. {
  1228. uint32 destaddr = 0L;
  1229. #ifdef HOPPER
  1230. struct route *rp;
  1231. #endif
  1232.  
  1233. #ifdef SMTPTRACE
  1234.     if (Smtptrace > 6)
  1235.         tcmdprintf ("MX lookup for = %s\n", dest);
  1236. #endif
  1237.  
  1238. #ifdef HOPPER
  1239.     if (*dest == '\0') {
  1240. #ifdef SMTPTRACE
  1241.         if (Smtptrace > 6)
  1242.             tcmdprintf ("Local mail\n");
  1243. #endif
  1244.         return Ip_addr;
  1245.     }
  1246. #endif
  1247.  
  1248.     /* look up address or use the gateway */
  1249.     if (UseMX) {
  1250.         destaddr = resolve_mx (dest);
  1251. #ifdef SMTPTRACE
  1252.         if (Smtptrace > 6)
  1253.             tcmdprintf ("MX lookup returned = %s\n", inet_ntoa (destaddr));
  1254. #endif
  1255.     }
  1256.     kwait (NULL);
  1257.     if (destaddr == 0L)
  1258.         if ((destaddr = resolve (dest)) == 0L)
  1259.             if (Gateway != 0)
  1260.                 destaddr = Gateway;    /* Use the gateway  */
  1261.  
  1262. #ifdef SMTPTRACE
  1263.     if (Smtptrace > 6)
  1264.         tcmdprintf ("Address resolver returned = %s\n", inet_ntoa (destaddr));
  1265. #endif
  1266.  
  1267. #ifdef HOPPER
  1268.     if (UseHopper && (destaddr != Ip_addr)) {
  1269.         if ((rp = rt_lookup (destaddr)) != NULLROUTE)
  1270.             if (rp->gateway != 0L)
  1271.                 destaddr = rp->gateway;
  1272. #ifdef SMTPTRACE
  1273.         if (Smtptrace > 6)
  1274.             tcmdprintf ("Hopper returned = %s\n", inet_ntoa (destaddr));
  1275. #endif
  1276.     }
  1277. #endif
  1278.  
  1279. #ifdef SMTPTRACE
  1280.     if (Smtptrace > 6)
  1281.         tcmdprintf ("Mailroute returned = %s\n", inet_ntoa (destaddr));
  1282. #endif
  1283.     return destaddr;
  1284. }
  1285.  
  1286.  
  1287.  
  1288. /* save line in error list */
  1289. static void
  1290. logerr (struct smtpcli *cb, char *line)
  1291. {
  1292. register struct list *lp, *tp;
  1293.  
  1294.     tp = (struct list *) callocw (1, sizeof (struct list));
  1295.  
  1296.     tp->val = strdup (line);
  1297.     /* find end of list */
  1298.     if ((lp = cb->errlog) == NULLLIST)
  1299.         cb->errlog = tp;
  1300.     else {
  1301.         while (lp->next != NULLLIST)
  1302.             lp = lp->next;
  1303.         lp->next = tp;
  1304.     }
  1305. }
  1306.  
  1307.  
  1308.  
  1309. static int
  1310. smtpsendfile (register struct smtpcli *cb)
  1311. {
  1312. int error = 0;
  1313. int lastlineCR = 1;
  1314.  
  1315.     strcpy (cb->buf, "\n");
  1316.     while (fgets (cb->buf, sizeof (cb->buf), cb->tfile) != NULLCHAR) {
  1317.         /* Escape a '.' character at the beginning of a line */
  1318.         if (*(cb->buf) == '.')
  1319.             usputc (cb->s, '.');
  1320.         usputs (cb->s, cb->buf);
  1321.         /* Did this line end in CR? */
  1322.         lastlineCR = (cb->buf[strlen (cb->buf) - 1] == '\n');
  1323.         kwait (NULL);
  1324.     }
  1325.     (void) fclose (cb->tfile);
  1326.     cb->tfile = NULLFILE;
  1327.     /* Send the end-of-message command */
  1328.     if (lastlineCR)
  1329.         sendcmd (cb, ".\n");
  1330.     else
  1331.         sendcmd (cb, "\n.\n");
  1332.     return error;
  1333. }
  1334.  
  1335.  
  1336.  
  1337. /* do a printf() on the socket with optional local tracing */
  1338. static void
  1339. sendcmd (struct smtpcli *cb, const char *fmt,...)
  1340. {
  1341. va_list args;
  1342.  
  1343.     va_start (args, fmt);    /*lint !e718 !e746 */
  1344.     (void) vsprintf (cb->buf, fmt, args);
  1345. #ifdef    SMTPTRACE
  1346.     if (Smtptrace) {
  1347.         tcmdprintf ("smtp sent: ");
  1348. #ifdef UNIX
  1349.         sm_status (0, cb->buf);
  1350. #else
  1351.         (void) usvprintf (Curproc->output, fmt, args);
  1352. #endif
  1353.     }
  1354. #endif
  1355.     usputs (cb->s, cb->buf);
  1356.     va_end (args);
  1357. }
  1358.  
  1359.  
  1360.  
  1361. /* Wait for, read and display response from server. Return the result code. */
  1362. static int
  1363. getresp (
  1364. struct smtpcli *cb,
  1365. char *usebuf,
  1366. int mincode            /* Keep reading until at least this code comes back */
  1367. ) {
  1368. int rval;
  1369. char buf[LINELEN], *line;
  1370.  
  1371.     line = (usebuf) ? usebuf : buf;
  1372.     usflush (cb->s);
  1373.     for (;;) {
  1374.         kwait (NULL);
  1375.         /* Get line */
  1376.         kalarm (Smtpt4 * 1000L);    /* set a timeout */
  1377.         if (recvline (cb->s, (unsigned char *) line, LINELEN) == -1) {
  1378.             kalarm (0L);    /* reset a timeout */
  1379.             log (cb->s, "SMTP Client timeout waiting for response");
  1380.             rval = -1;
  1381.             break;
  1382.         }
  1383.         kalarm (0L);    /* reset a timeout */
  1384.         rip (line);    /* Remove cr/lf */
  1385.         rval = atoi (line);
  1386. #ifdef    SMTPTRACE
  1387.         if (Smtptrace)
  1388.             tcmdprintf (smtp_recv, line);    /* Display to user */
  1389. #endif
  1390.         if (rval >= 500) {    /* Save permanent error replies */
  1391.             char tmp[LINELEN];
  1392.  
  1393.             if (cb->errlog == NULLLIST) {
  1394.                 sprintf (tmp, "While talking to %s:",
  1395.                      cb->destname);
  1396.                 logerr (cb, tmp);
  1397.             }
  1398.             if (cb->buf[0] != '\0') {    /* Save offending command */
  1399.                 rip (cb->buf);
  1400.                 sprintf (tmp, ">>> %s", cb->buf);
  1401.                 logerr (cb, tmp);
  1402.                 cb->buf[0] = '\0';
  1403.             }
  1404.             sprintf (tmp, "<<< %s", line);
  1405.             logerr (cb, tmp);    /* save the error reply */
  1406.         }
  1407.         /* Messages with dashes are continued */
  1408.         if (line[3] != '-' && rval >= mincode)
  1409.             break;
  1410.     }
  1411.     return rval;
  1412. }
  1413.